use std::str::FromStr;
use async_graphql::*;
use redis::aio::MultiplexedConnection;
use sea_orm::{DatabaseConnection};
use serde::{Deserialize, Serialize};
use sqlx::types::Decimal;
use tracing::info;
use crate::entity::{user_account, user_auth_role};
use crate::handler::user_handler::{add_user_account, add_user_address, add_user_cart_item, add_user_collection, delete_user, delete_user_account, delete_user_address, delete_user_cart_item, delete_user_collection, get_user_by_id, get_users, login, logout, open_user_wallet, recharge_user_wallet, refresh_token_handler, registry_user_form, update_user_address, update_user_cart_item, update_user_info};
use crate::graphql::AuthGuard;
use crate::utility::jwt::UserInfo;

#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserAddressObject {
    pub id: String,
    pub user_id: String,
    pub recipient_name: String,
    pub phone: String,
    pub province: String,
    pub city: String,
    pub district: String,
    pub detail: String,
    pub is_default: bool,
    pub tag: String,
    pub create_time: String,
    pub update_time: String,
}


#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserAuthorityObject {
    pub id: String,
    pub name: String,
    pub user_id: String,
    pub authority_id: String,
    pub create_time: String,
    pub update_time: String,
}


#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserRoleObject {
    pub id: String,
    pub name: String,
    pub user_id: String,
    pub role_id: String,
    pub create_time: String,
    pub update_time: String,
}

impl From<user_auth_role::Model> for UserRoleObject {
    fn from(model: user_auth_role::Model) -> Self {
        Self {
            id: model.id.to_string(),
            name: model.name,
            user_id: model.user_id.to_string(),
            role_id: model.role_id.to_string(),
            create_time: model.create_time.format("%Y-%m-%d %H:%M:%S").to_string(),
            update_time: model.update_time.format("%Y-%m-%d %H:%M:%S").to_string(),
        }
    }
}

#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserAccountObject {
    pub id: String,
    pub user_id: String,
    pub r#type: String,
    pub account: String,
    pub access_code: Option<String>,
    pub create_time: String,
    pub update_time: String,
}

impl From<user_account::Model> for UserAccountObject {
    fn from(model: user_account::Model) -> Self {
        Self {
            id: model.id.to_string(),
            user_id: model.user_id.to_string(),
            r#type: model.r#type,
            account: model.account,
            access_code: model.access_code,
            create_time: model.create_time.format("%Y-%m-%d %H:%M:%S").to_string(),
            update_time: model.update_time.format("%Y-%m-%d %H:%M:%S").to_string(),
        }
    }
}

#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserCartItemObject {
    pub id: String,
    pub user_id: String,
    pub product_id: String,
    pub quantity: u32,
    pub create_time: String,
    pub update_time: String,
}


#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserCollectionObject {
    pub id: String,
    pub user_id: String,
    pub product_id: String,
    pub create_time: String,
    pub update_time: String,
}

#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserWalletObject {
    pub id: String,
    pub user_id: String,
    pub balance: String,
    pub create_time: String,
    pub update_time: String,
}


#[derive(Debug, Clone, SimpleObject , Deserialize, Serialize)]
pub struct UserTokenObject {
    pub access_token: String,
    pub refresh_token: Option<String>,
}

#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserLoginObject {
    pub id: String,
    pub username: String,
    pub nickname: String,
    pub avatar_addr: String,
    pub status: String,
    pub roles: Vec<UserRoleObject>,
    pub authorities: Vec<UserAuthorityObject>,
    pub accounts: Vec<UserAccountObject>,
    pub access_token: String,
    pub refresh_token: String,
    pub create_time: String,
    pub update_time: String,
}


#[derive(Debug, Clone, SimpleObject, Deserialize, Serialize)]
pub struct UserObject {
    pub id: String,
    pub username: String,
    pub nickname: String,
    pub avatar_addr: String,
    pub status: String,
    pub create_time: String,
    pub update_time: String,
    pub accounts: Vec<UserAccountObject>,
    pub addresses: Vec<UserAddressObject>,
    pub roles: Vec<UserRoleObject>,
    pub authorities: Vec<UserAuthorityObject>,
    pub cart_items: Vec<UserCartItemObject>,
    pub collections: Vec<UserCollectionObject>,
    pub wallet: Option<UserWalletObject>,
}

#[derive(Default)]
pub struct UserQuery;

#[Object]
impl UserQuery {

    #[graphql(guard = "AuthGuard(\"user:select\")")]
    pub async fn users(
        &self,
        ctx: &Context<'_>,
    ) -> Result<Option<Vec<UserObject>>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;

        // 获取用户列表的处理逻辑
        // 这里暂时返回一个空的向量
        get_users(db, conn).await
    }

    #[graphql(guard = "AuthGuard(\"user:select_by_id\")")]
    pub async fn user_by_id(
        &self,
        ctx: &Context<'_>,
        id: String,
    ) -> Result<Option<UserObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        get_user_by_id(db, id).await
    }

    #[graphql(guard = "AuthGuard(\"\")")]
    async fn current_user(
        &self,
        ctx: &Context<'_>,
    ) -> Result<Option<UserObject>> {
        // 这里应该从认证信息中获取当前用户ID
        let user_info = ctx.data::<UserInfo>()?;
        // 暂时返回示例数据
        let db = ctx.data::<DatabaseConnection>()?;
        info!("current_user: {:?}", user_info);
        // 假设从上下文中获取用户ID
        get_user_by_id(db, user_info.user_id.to_string()).await
    }
}


// 添加注册输入参数结构体
#[derive(InputObject, Deserialize, Serialize)]
pub struct RegisterUserInput {
    pub username: String,
    pub password: String,
    pub nickname: Option<String>,
    pub avatar_addr: Option<String>,
    pub email: Option<String>,
}

#[derive(InputObject)]
pub struct UpdateUserInput {
    pub nickname: Option<String>,
    pub avatar_addr: Option<String>,
}

// 用户账户输入对象
#[derive(InputObject)]
pub struct UserAccountInput {
    pub r#type: String,
    pub account: String,
    pub access_code: Option<String>,
}

// 用户地址输入对象
#[derive(InputObject)]
pub struct UserAddressInput {
    pub recipient_name: String,
    pub phone: String,
    pub province: String,
    pub city: String,
    pub district: String,
    pub detail: String,
    pub tag: String,
    pub is_default: bool,
}


// 登录输入参数结构体
#[derive(InputObject, Deserialize, Serialize)]
pub struct LoginUserInput {
    pub username: String,
    pub password: String,
}

// 钱包充值输入对象
#[derive(InputObject)]
pub struct UserWalletRechargeInput {
    pub amount: String, // 使用字符串避免精度问题
    pub pay_password: String,
    pub channel_type: String,
    pub channel_id: String,
}

impl UserWalletRechargeInput {
    pub fn amount_decimal(&self) -> Result<Decimal, async_graphql::Error> {
        Decimal::from_str(&self.amount)
            .map_err(|_| async_graphql::Error::new("金额格式错误"))
    }
}

// 添加用户注册的 mutation
#[derive(Default)]
pub struct UserMutation;

#[Object]
impl UserMutation {
    async fn register_user(
        &self,
        ctx: &Context<'_>,
        input: RegisterUserInput,
    ) -> Result<UserLoginObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn =  ctx.data::<MultiplexedConnection>()?;
        registry_user_form(db, conn, input).await
    }

    async fn login_user(
        &self,
        ctx: &Context<'_>,
        input: LoginUserInput,
    ) -> Result<UserLoginObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn =  ctx.data::<MultiplexedConnection>()?;

        login(db, conn, input).await
    }

    #[graphql(guard = "AuthGuard(\"user:delete\")")]
    async fn delete_user(
        &self,
        ctx: &Context<'_>,
        id: String,
    ) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        let redis_conn = ctx.data::<MultiplexedConnection>()?;

        delete_user(db, redis_conn, id).await
    }
    
    async fn refresh_token(
        &self,
        ctx: &Context<'_>,
        refresh_token: String,
    ) -> Result<UserTokenObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn =  ctx.data::<MultiplexedConnection>()?;

        refresh_token_handler(db, conn, &*refresh_token).await
    }

    #[graphql(guard = "AuthGuard(\"\")")]
    async fn logout(
        &self,
        ctx: &Context<'_>,
    ) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn =  ctx.data::<MultiplexedConnection>()?;

        // 这里应该从认证信息中获取当前用户ID
        let user_info = ctx.data::<UserInfo>()?;
        // 暂时返回示例数据
        let db = ctx.data::<DatabaseConnection>()?;

        logout(db, conn, user_info.user_id).await
    }


    #[graphql(guard = "AuthGuard(\"user:update\")")]
    async fn update_user_status(
        &self,
        ctx: &Context<'_>,
        user_id: String,
        status: String,
    ) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        update_user_info(db, user_id, None, None, Some(status)).await

    }


    /// 更新当前用户信息
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn update_current_user(
        &self,
        ctx: &Context<'_>,
        input: UpdateUserInput,
    ) -> Result<bool> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        update_user_info(db, user_info.user_id.to_string(), input.nickname, input.avatar_addr, None).await
    }


    /// 为当前用户新增账户
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn add_current_user_account(
        &self,
        ctx: &Context<'_>,
        input: UserAccountInput,
    ) -> Result<UserAccountObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        add_user_account(db, user_info.user_id, input).await
    }


    /// 删除当前用户的账户
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn delete_current_user_account(
        &self,
        ctx: &Context<'_>,
        account_id: String,
    ) -> Result<bool> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        delete_user_account(db, user_info.user_id, account_id).await
    }



    /// 为当前用户新增地址
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn add_current_user_address(
        &self,
        ctx: &Context<'_>,
        input: UserAddressInput,
    ) -> Result<UserAddressObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        add_user_address(db, user_info.user_id, input).await
    }


    /// 删除当前用户的地址
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn delete_current_user_address(
        &self,
        ctx: &Context<'_>,
        address_id: String,
    ) -> Result<bool> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        delete_user_address(db, user_info.user_id, address_id).await
    }



    /// 更新当前用户的地址
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn update_current_user_address(
        &self,
        ctx: &Context<'_>,
        address_id: String,
        input: UserAddressInput,
    ) -> Result<UserAddressObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        update_user_address(db, user_info.user_id, address_id, input).await
    }



    /// 为当前用户新增购物车商品
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn add_current_user_cart_item(
        &self,
        ctx: &Context<'_>,
        product_id: String,
        quantity: u32,
    ) -> Result<UserCartItemObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        add_user_cart_item(db, user_info.user_id, product_id, quantity).await
    }



    /// 更新当前用户购物车商品数量
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn update_current_user_cart_item(
        &self,
        ctx: &Context<'_>,
        cart_item_id: String,
        quantity: u32,
    ) -> Result<UserCartItemObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        update_user_cart_item(db, user_info.user_id, cart_item_id, quantity).await
    }



    /// 删除当前用户的购物车商品
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn delete_current_user_cart_item(
        &self,
        ctx: &Context<'_>,
        cart_item_id: String,
    ) -> Result<bool> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        delete_user_cart_item(db, user_info.user_id, cart_item_id).await
    }


    /// 为当前用户新增收藏商品
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn add_current_user_collection(
        &self,
        ctx: &Context<'_>,
        product_id: String,
    ) -> Result<UserCollectionObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        add_user_collection(db, user_info.user_id, product_id).await
    }



    /// 删除当前用户的收藏商品
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn delete_current_user_collection(
        &self,
        ctx: &Context<'_>,
        collection_id: String,
    ) -> Result<bool> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        delete_user_collection(db, user_info.user_id, collection_id).await
    }




    /// 为当前用户开通钱包
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn open_current_user_wallet(
        &self,
        ctx: &Context<'_>,
        pay_password: String,
    ) -> Result<UserWalletObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        open_user_wallet(db, user_info.user_id, pay_password).await
    }



    /// 当前用户钱包充值
    #[graphql(guard = "AuthGuard(\"\")")]
    async fn recharge_current_user_wallet(
        &self,
        ctx: &Context<'_>,
        input: UserWalletRechargeInput,
    ) -> Result<UserWalletObject> {
        let user_info = ctx.data::<UserInfo>()?;
        let db = ctx.data::<DatabaseConnection>()?;
        let amount = input.amount_decimal()?;
        recharge_user_wallet(db, user_info.user_id, amount, input.channel_type, input.channel_id, input.pay_password).await
    }
}
